﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VisualStateManager
{
    public static class ControlOperatorManager
    {
        private static List<BaseControlOperator> operators;
        private static Dictionary<Type, BaseControlOperator> cache;

        private static BaseControlOperator GetOperatorFromList(object control)
        {
            BaseControlOperator @operator = null;
            Type controlType = control.GetType();

            for (int i = 0; i < operators.Count; i++)
            {
                if (controlType.IsSubclassOf(operators[i].AcceptedType) || controlType == operators[i].AcceptedType)
                {
                    @operator = operators[i];
                    break;
                }
            }

            return @operator;
        }

        private static BaseControlOperator GetOperator(object control)
        {
            BaseControlOperator @operator;

            Type type = control.GetType();
            if (cache.ContainsKey(type))
            {
                @operator = cache[type];
                if (@operator == null)
                    throw new InvalidOperationException("Damaged cache!");
            }
            else
            {
                @operator = GetOperatorFromList(control);
                if (@operator == null)
                    throw new InvalidOperationException("Unsupported control!");

                cache[control.GetType()] = @operator;
            }
            return @operator;
        }

        static ControlOperatorManager()
        {
            operators = new List<BaseControlOperator>();
            cache = new Dictionary<Type, BaseControlOperator>();

            AddOperator(new ObjectOperator());
            AddOperator(new ControlOperator());
            AddOperator(new ToolStripMenuItemOperator());
            AddOperator(new ToolStripButtonOperator());
            AddOperator(new ToolStripSplitButtonOperator());
        }

        public static void AddOperator(BaseControlOperator newOperator)
        {
            if (newOperator == null)
                throw new ArgumentNullException("newOperator");

            int index = operators.FindIndex(p => p.AcceptedType == newOperator.AcceptedType);
            if (index > 0)
                operators[index] = newOperator;
            else
            {
                index = operators.Count;

                for (int i = operators.Count - 1; i >= 0; i--)
                {
                    if (newOperator.AcceptedType.IsSubclassOf(operators[i].AcceptedType))
                        index = i;
                }

                operators.Insert(index, newOperator);
            }

            cache.Clear();
        }

        public static void RemoveOperator(BaseControlOperator oldOperator)
        {
            if (oldOperator == null)
                throw new ArgumentNullException("oldOperator");

            operators.Remove(oldOperator);

            cache.Clear();
        }

        public static void SetEnabled(object control, bool value)
        {
            BaseControlOperator @operator = GetOperator(control);

            @operator.SetEnabled(control, value);
        }

        public static void SetChecked(object control, bool value)
        {
            BaseControlOperator @operator = GetOperator(control);

            @operator.SetChecked(control, value);
        }

        public static void SetVisible(object control, bool value)
        {
            BaseControlOperator @operator = GetOperator(control);

            @operator.SetVisible(control, value);
        }

        public static void HookClickEvent(object control, EventHandler clickHandler)
        {
            BaseControlOperator @operator = GetOperator(control);

            @operator.HookClickEvent(control, clickHandler);
        }

        public static void UnhookClickEvent(object control, EventHandler clickHandler)
        {
            BaseControlOperator @operator = GetOperator(control);

            @operator.UnhookClickEvent(control, clickHandler);
        }
    }
}
